package http

import (
	"bytes"
	"compress/gzip"
	"context"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

type Params map[string]interface{}
type Headers map[string]string

func Request(method , url string, params Params, headers Headers) ([]byte, error) {
	paramsBytes, err := json.Marshal(params)
	if err != nil {
		return nil, err
	}
	req, _ := http.NewRequest(method, url, bytes.NewReader(paramsBytes))

	req.Header.Add("Content-Type", "application/json;charset=UTF-8")
	for key, val := range headers{
		req.Header.Add(key, val)
	}

	ctx, _ := context.WithTimeout(context.Background(), 3000 * time.Millisecond)
	req = req.WithContext(ctx)

	response, err := (&http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}).Do(req)

	if err != nil {
		return nil, err
	}

	if response.StatusCode != http.StatusOK{
		return nil, errors.New("StatusCode " + fmt.Sprintf("%d", response.StatusCode))
	}

	var body []byte
	switch response.Header.Get("Content-Encoding") {
		case "gzip":
			reader, _ := gzip.NewReader(response.Body)
			for {
				buf := make([]byte, 1024)
				n, err := reader.Read(buf)

				if err != nil && err != io.EOF {
					return nil, err
				}

				if n == 0 {
					break
				}
				body = append(body, buf...)
			}
		default:
			body, _ = ioutil.ReadAll(response.Body)

	}

	return body, nil
}


func Dial(ctx context.Context, method string, url string, params Params, headers Headers) ([]byte, error) {
	paramsBytes, err := json.Marshal(params)
	if err != nil {
		return nil, err
	}
	req, _ := http.NewRequest(strings.ToUpper(method), url, bytes.NewReader(paramsBytes))

	req.Header.Add("Content-Type", "application/json;charset=UTF-8")
	for key, val := range headers{
		req.Header.Add(key, val)
	}

	req = req.WithContext(ctx)
	response, err := (&http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}).Do(req)

	if err != nil {
		return nil, err
	}

	if response.StatusCode != http.StatusOK{
		return nil, errors.New("StatusCode " + fmt.Sprintf("%d", response.StatusCode))
	}

	var body []byte
	body, _ = ioutil.ReadAll(response.Body)
	return body, nil
}


func Get(url string) ([]byte, error) {
	client := &http.Client{Timeout: 2 * time.Second}
	resp, err := client.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var buffer [512]byte
	result := bytes.NewBuffer(nil)
	for {
		n, err := resp.Body.Read(buffer[0:])
		result.Write(buffer[0:n])
		if err != nil && err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
	}

	return result.Bytes(), nil
}
